package co.recloud.ariadne.request;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import co.recloud.ariadne.model.Buffers;
import co.recloud.ariadne.model.Host;
import co.recloud.ariadne.model.Location;
import co.recloud.ariadne.model.logical.Transaction;
import co.recloud.ariadne.thread.Main;
import com.google.protobuf.Message;
import com.sun.tools.javac.util.Pair;

public class DataRequest extends Request {
	/**
	 * 
	 */
	private static final long serialVersionUID = 9126451398829682154L;
	public static final int GET = 1;
	public static final int PUT = 2;
	private Buffers.DataRequest.Builder builder;

    public DataRequest() {
        builder = Buffers.DataRequest.newBuilder();
        setBufferType(Request.PROTOCOL_BUFFER);
        setTime(Main.getTime());
    }
	/**
	 * @return the transaction
	 */
	public Transaction getTransaction() {
        Transaction transaction = null;
        if(builder.hasTransaction()) {
            transaction = new Transaction();
            Buffers.Transaction txn = builder.getTransaction();
            if(txn.hasCommitTime()) {
                transaction.setCommitTime(txn.getCommitTime());
            }
            if(txn.hasId()) {
                transaction.setId(txn.getId());
            }
            if(txn.hasStartTime()) {
                transaction.setStartTime(txn.getStartTime());
            }
            if(txn.hasState()) {
                transaction.setState(txn.getState());
            }
        }
		return transaction;
	}
	/**
	 * @param transaction the transaction to set
	 */
	public void setTransaction(Transaction transaction) {
        Buffers.Transaction.Builder txnBuilder = Buffers.Transaction.newBuilder();
        if(transaction.getCommitTime() != null) {
            txnBuilder.setCommitTime(transaction.getCommitTime());
        }
        if(transaction.getId() != null) {
            txnBuilder.setId(transaction.getId());
        }
        if(transaction.getStartTime() != null) {
            txnBuilder.setStartTime(transaction.getStartTime());
        }
        txnBuilder.setState(transaction.getState());
        builder.setTransaction(txnBuilder.build());
	}
	/**
	 * @return the schema
	 */
	public String getSchema() {
		return builder.getSchema();
	}
	/**
	 * @param schema the schema to set
	 */
	public void setSchema(String schema) {
		builder.setSchema(schema);
	}
	/**
	 * @return the columnFamily
	 */
	public String getColumnFamily() {
		return builder.getColumnFamily();
	}
	/**
	 * @param columnFamily the columnFamily to set
	 */
	public void setColumnFamily(String columnFamily) {
		builder.setColumnFamily(columnFamily);
	}
	/**
	 * @return the key
	 */
	public String getKey() {
		return builder.getKey();
	}
	/**
	 * @param key the key to set
	 */
	public void setKey(String key) {
		builder.setKey(key);
	}
	/**
	 * @param type the type to set
	 */
	public void setType(int type) {
		builder.setType(type);
	}
	/**
	 * @return the type
	 */
	public int getType() {
		return builder.getType();
	}
	/**
	 * @param data the data to set
	 */
	public void setData(Map<String,Map<String,Map<String,Map<String,Object>>>> data) {
        builder.clearData();
		for(String schema : data.keySet()) {
            Buffers.DataRequest.DataSet.Builder schemaBuilder = Buffers.DataRequest.DataSet.newBuilder();
            schemaBuilder.setSchema(schema);
            for(String columnFamily : data.get(schema).keySet()) {
                Buffers.DataRequest.DataSet.ColumnFamilySet.Builder cfBuilder = Buffers.DataRequest.DataSet.ColumnFamilySet.newBuilder();
                cfBuilder.setColumnFamily(columnFamily);
                for(String key : data.get(schema).get(columnFamily).keySet()) {
                    Buffers.DataRequest.DataSet.ColumnFamilySet.KeySet.Builder keyBuilder = 
                            Buffers.DataRequest.DataSet.ColumnFamilySet.KeySet.newBuilder();
                    keyBuilder.setKey(key);
                    for(String column : data.get(schema).get(columnFamily).get(key).keySet()) {
                        Buffers.DataRequest.DataSet.ColumnFamilySet.KeySet.ColumnSet.Builder columnBuilder =
                                Buffers.DataRequest.DataSet.ColumnFamilySet.KeySet.ColumnSet.newBuilder();
                        columnBuilder.setColumn(column);
                        columnBuilder.setData(data.get(schema).get(columnFamily).get(key).get(column).toString());
                        keyBuilder.addColumns(columnBuilder.build());
                    }
                    cfBuilder.addKeys(keyBuilder.build());
                }
                schemaBuilder.addColumnFamilies(cfBuilder.build());
            }
            builder.addData(schemaBuilder.build());
        }
	}
	/**
	 * @return the data
	 */
	public Map<String,Map<String,Map<String,Map<String,Object>>>> getData() {
        Map<String,Map<String,Map<String,Map<String,Object>>>> data = new HashMap<String, Map<String, Map<String, Map<String, Object>>>>();
        for(Buffers.DataRequest.DataSet schema : builder.getDataList()) {
            data.put(schema.getSchema(), new HashMap<String, Map<String, Map<String, Object>>>());
            for(Buffers.DataRequest.DataSet.ColumnFamilySet cf : schema.getColumnFamiliesList()) {
                data.get(schema.getSchema()).put(cf.getColumnFamily(), new HashMap<String, Map<String, Object>>());
                for(Buffers.DataRequest.DataSet.ColumnFamilySet.KeySet key : cf.getKeysList()) {
                    data.get(schema.getSchema()).get(cf.getColumnFamily()).put(key.getKey(), new HashMap<String, Object>());
                    for(Buffers.DataRequest.DataSet.ColumnFamilySet.KeySet.ColumnSet column : key.getColumnsList()) {
                        data.get(schema.getSchema()).get(cf.getColumnFamily()).get(key.getKey()).put(column.getColumn(), column.getData());
                    }
                }
            }
        }
		return data;
	}
	/**
	 * @param columns the columns to set
	 */
	public void setColumns(Set<String> columns) {
        builder.clearColumns();
        if(columns != null) {
		    builder.addAllColumns(columns);
        }
	}
	/**
	 * @return the columns
	 */
	public Set<String> getColumns() {
        HashSet<String> columns = new HashSet<String>();
        columns.addAll(builder.getColumnsList());
        return columns;
    }
	/**
	 * @param primary the primary to set
	 */
	public void setPrimary(Location primary) {
		builder.setLocation(
                Buffers.Location.newBuilder()
                .setX(primary.getX())
                .setY(primary.getY()).build());
	}
	/**
	 * @return the primary
	 */
	public Location getPrimary() {
		Location location = new Location();
        location.setX(builder.getLocation().getX());
        location.setY(builder.getLocation().getY());
        return location;
	}

    @Override
    public Message getMessage() {
         return builder.build();
    }
    
    @Override
    public void loadFromMessage(Message message) {
        this.builder = ((Buffers.DataRequest) message).toBuilder();
    }
    
    @Override
    public void setTime(Long time) {
        this.builder.getRequestBuilder().setTime(time);
    }
    
    @Override 
    public Long getTime() {
        return this.builder.getRequest().getTime();        
    }
    
    @Override
    public void setTarget(Host target) {
        Buffers.Host.Builder targetBuilder = builder.getRequestBuilder().getTargetBuilder();
        Buffers.Location.Builder locationBuilder = targetBuilder.getLocationBuilder();
        targetBuilder.setName(target.getHostName());
        targetBuilder.setPort(target.getPort());
        targetBuilder.setToken(target.getToken().intValue());
        locationBuilder.setX(target.getLocation().getX());
        locationBuilder.setY(target.getLocation().getY());
    }
    
    @Override
    public Host getTarget() {
        Host target = new Host();
        target.setLocation(new Location());
        target.setHostName(builder.getRequest().getTarget().getName());
        target.setPort(builder.getRequest().getTarget().getPort());
        target.setToken((long) builder.getRequest().getTarget().getToken());
        target.getLocation().setX(builder.getRequest().getTarget().getLocation().getX());
        target.getLocation().setY(builder.getRequest().getTarget().getLocation().getY());
        return target;
    }

    @Override
    public void setResponseExpected(boolean expected) {
        builder.getRequestBuilder().setResponseExpected(expected);
    }

    @Override
    public boolean isResponseExpected() {
        return builder.getRequest().getResponseExpected();
    }
}
